package com.jiubanqingchen.future.common.plugin.quartz;

import com.jfinal.ext.kit.DateKit;
import com.jiubanqingchen.future.model.models.CronTask;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * 定时任务管理类
 *
 * @author light_dust
 * @Date 2020/5/21
 */
public class QuartzManager {
    
    private static Logger logger = LoggerFactory.getLogger(QuartzManager.class);

    private static Scheduler scheduler;

    public static void init() {
        try {
            SchedulerFactory schedulerFactory = new StdSchedulerFactory("quartz.properties");
            //实例化调度器
            scheduler = schedulerFactory.getScheduler();
        } catch (Exception e) {
            logger.error("QuartzManager init failed", e);
        }

    }

    public static void start() {
        if (scheduler == null) init();
        try {
            if (!scheduler.isStarted()) {
                scheduler.start();
            }
        } catch (SchedulerException e) {
            logger.error("QuartzManager start failed", e);
        }
    }

    public static void stop() {
        if (scheduler == null)
            throw new NullPointerException("You can't stop this scheduler because this scheduler is null");
        try {
            if (!scheduler.isShutdown()) {
                scheduler.shutdown();
            }
        } catch (SchedulerException e) {
            logger.error("QuartzManager stop failed", e);
        }
    }

    /**
     * 添加定时任务
     *
     * @param cronTask
     */
    public static void addJob(CronTask cronTask) {
        //得到计划任务表达式
        String cronExpression = cronTask.getCronExpression();
        //得到执行类名称
        String className = cronTask.getClassName();
        String cronTaskName = cronTask.getCronTaskName();

        try {
            JobKey key = getJobKey(cronTask.getCronTaskId());
            Class<?> cls = Class.forName(className);

            if (Job.class.isAssignableFrom(cls)) {
                Class<? extends Job> jobClass = (Class<? extends Job>) cls;
                addJob(key, cronTaskName, cronExpression, jobClass);
            } else {
                logger.info("load job failed. " + className);
            }
        } catch (Exception e) {
            logger.warn("no class find with {}", className);
        }
    }

    /**
     * 添加一个任务
     *
     * @param jobKey
     * @param cronTaskName
     * @param cronExpression
     * @param jobClass
     */
    public static void addJob(JobKey jobKey, String cronTaskName, String cronExpression, Class<? extends Job> jobClass) {
        if (jobClass != null) {
            try {
                JobBuilder build = JobBuilder.newJob(jobClass);
                //创建JobDetail实例
                JobDetail jobDetail = build.withIdentity(jobKey).build();

                //创建trigger实例
                TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
                CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();

                Trigger trigger = triggerBuilder.withIdentity(getTriggerKey(jobKey.toString())).withSchedule(cron).build();
                scheduler.scheduleJob(jobDetail, trigger);
                logger.info(jobKey.getName() + cronTaskName + " 将在 " + DateKit.toStr(trigger.getNextFireTime(), DateKit.timeStampPattern) + " 运行...\r\n");
            } catch (Exception e) {
                logger.error(jobKey.getName() + " ERROR:" + e.getMessage(), e);
            }
        }
    }

    /**
     * 初始化所有任务
     */
    public static void addAllJob(List<CronTask> cronTaskList) {
        if (cronTaskList == null || cronTaskList.isEmpty()) {
            logger.info("没有配置后台定时任务工作计划!");
            return;
        }
        for (CronTask cronTask : cronTaskList) {
            addJob(cronTask);
        }
    }

    /**
     * 暂停任务
     *
     * @param cronTask
     */
    public static void pauseJob(CronTask cronTask) {
        JobKey jobKey = getJobKey(cronTask.getCronTaskId());
        TriggerKey triggerKey = getTriggerKey(jobKey.toString());
        try {
            if (scheduler.checkExists(jobKey)) {
                scheduler.pauseJob(jobKey);//暂停任务
                logger.info("任务:{" + cronTask.getCronTaskName() + "}暂停成功");
            }
        } catch (SchedulerException e) {
            logger.warn("pause Job cronTaskName: {} failed", jobKey.getName() + cronTask.getCronTaskName(), e);
        }
    }

    /**
     * 恢复任务
     *
     * @param cronTask
     */
    public static void resumeJob(CronTask cronTask) throws Exception {
        JobKey jobKey = getJobKey(cronTask.getCronTaskId());
        TriggerKey triggerKey = getTriggerKey(jobKey.toString());
        try {
            if (scheduler.checkExists(jobKey)) {
                scheduler.resumeJob(jobKey);//重启任务
                logger.info("任务:{" + cronTask.getCronTaskName() + "}恢复成功");
            }
        } catch (SchedulerException e) {
            logger.warn("pause Job resumeJob: {} failed", jobKey.getName() + cronTask.getCronTaskName(), e);
        }
    }

    /**
     * 执行一次定时任务
     *
     * @param cronTask
     */
    public static void runOnceJob(CronTask cronTask) {
        JobKey jobKey = getJobKey(cronTask.getCronTaskId());
        TriggerKey triggerKey = getTriggerKey(jobKey.toString());
        try {
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (trigger == null) {//如果当前任务不存在则新增
                addJob(cronTask);//新增任务 直接暂停
                pauseJob(cronTask);
            }
            scheduler.triggerJob(jobKey);
            logger.info("任务:{" + cronTask.getCronTaskName() + "}执行一次成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除某一个任务
     *
     * @param cronTask
     */
    public static void removeJob(CronTask cronTask) {
        JobKey jobKey = getJobKey(cronTask.getCronTaskId());
        TriggerKey triggerKey = getTriggerKey(jobKey.toString());
        try {
            if (scheduler.checkExists(triggerKey)) {
                scheduler.pauseTrigger(triggerKey);
                if (scheduler.checkExists(jobKey)) {
                    scheduler.unscheduleJob(triggerKey);
                    scheduler.deleteJob(jobKey);
                }
            }
            logger.info("任务:{" + cronTask.getCronTaskName() + "}移除成功");
        } catch (SchedulerException e) {
            logger.warn("remove Job jobName: {} failed", jobKey.getName() + cronTask.getCronTaskName(), e);
        }
    }

    /**
     * 更改任务的执行规则
     *
     * @param cronTask
     */
    public static void updateCronExpression(CronTask cronTask) {
        TriggerKey triggerKey = getTriggerKey(cronTask);
        try {
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (trigger == null) {
                return;
            }
            String oldCronExpression = trigger.getCronExpression();
            String cronExpression = cronTask.getCronExpression();
            if (!oldCronExpression.equalsIgnoreCase(cronTask.getCronExpression())) {
                // trigger已存在，则更新相应的定时设置
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
                // 按新的cronExpression表达式重新构建trigger
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
                // 按新的trigger重新设置job执行
                scheduler.rescheduleJob(triggerKey, trigger);
                logger.info("任务:{" + cronTask.getCronTaskName() + "}修改执行规则成功");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @param cronTask
     * @Description: 获取任务状态
     * NONE: 不存在
     * NORMAL: 正常
     * PAUSED: 暂停
     * COMPLETE:完成
     * ERROR : 错误
     * BLOCKED : 阻塞
     * @date 2018年5月21日 下午2:13:45
     */
    public static String getTriggerState(CronTask cronTask) {
        TriggerKey triggerKey = getTriggerKey(cronTask);
        String name = null;
        try {
            Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);
            name = triggerState.name();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return name;
    }

    /**
     * 得到JobKey
     *
     * @param cronTaskId
     * @return
     */
    public static JobKey getJobKey(String cronTaskId) {
        return JobKey.jobKey(getJobKeyName(cronTaskId), getJobKeyGroup(cronTaskId));
    }


    /**
     * 得到triggerKey
     *
     * @param jobKeyStr
     * @return
     */
    private static TriggerKey getTriggerKey(String jobKeyStr) {
        return TriggerKey.triggerKey(getTriggerName(jobKeyStr), getTriggerGroupName(jobKeyStr));
    }

    private static TriggerKey getTriggerKey(CronTask cronTask) {
        return getTriggerKey(getJobKey(cronTask.getCronTaskId()).toString());
    }

    private static String getJobKeyName(String cronTaskId) {
        return JobConstant.JOB_NAME + cronTaskId;
    }

    private static String getJobKeyGroup(String cronTaskId) {
        return JobConstant.JOB_GROUP + cronTaskId;
    }

    private static String getTriggerName(String jobKeyStr) {
        return JobConstant.TRIGGER_NAME + jobKeyStr;
    }

    private static String getTriggerGroupName(String jobKeyStr) {
        return JobConstant.TRIGGER_GROUP + jobKeyStr;
    }

}
